import 'dart:async';
import 'package:ble_helper_plugin/src/custom/custom_scan_result.dart';
import 'package:ble_helper_plugin/src/uuid_adapter_base.dart';
import 'package:ble_helper_plugin/src/custom/custom_connect_state.dart';
import 'package:ble_helper_plugin/src/interceptor_base.dart';
import 'package:ble_helper_plugin/src/handler_settings_base.dart';
import 'package:ble_helper_plugin/src/service_adapter.dart';
import 'package:ble_helper_plugin/src/handler_bluetooth_device.dart';
import 'package:ble_helper_plugin/src/utils.dart';
import 'package:ble_helper_plugin/src/waitting_stream.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

/*

这段代码定义了一个名为 `BluetoothManager` 的 Dart 类，用于管理蓝牙设备的扫描、连接和数据传输。以下是代码的概要：

- **单例模式**：`BluetoothManager` 类使用单例模式，确保只有一个实例存在。
- **StreamController**：用于管理蓝牙连接状态的流。
- **扫描设备**：提供了 `startScan` 和 `stopScan` 方法，用于开始和停止扫描蓝牙设备。
- **连接设备**：提供了 `connectDevice` 方法，用于连接到指定的蓝牙设备。
- **断开连接**：提供了 `disconnect` 方法，用于断开当前连接的蓝牙设备。
- **读写数据**：提供了 `write` 和 `read` 方法，用于向蓝牙设备写入和读取数据。
- **扫描结果处理**：通过 `_scanSubscription` 监听扫描结果，并根据需要过滤和处理扫描到的设备。
- **缓存读取值**：使用 `_readCache` 缓存读取的蓝牙数据。
- **超时处理**：在扫描和连接过程中设置了超时处理。

该类还包含一些辅助方法，如 `_hasRequiredServices` 用于检查设备是否包含所需的服务，
`_cancelScanningSubscription` 用于取消扫描订阅，
`_scanningHasStopped` 用于检查扫描是否已停止。

 */

// 扫码的设备回调
typedef CallbackScanResults = void Function(List<CustomScanResult>);

// 请求的回调
typedef CallbackResponse = void Function(List<int>);

/*
 * 蓝牙管理器 - 单例模式
 */
class BluetoothManager {
  // 单例
  static final BluetoothManager _instance = BluetoothManager._internal();
  factory BluetoothManager() => _instance;
  BluetoothManager._internal() {
    _initialized();
  }

  // 获取 Stream 对象 <BluetoothConnectState>
  Stream<CustomBluetoothConnectState> get bluetoothConnectState =>
      _connectStateController.stream;

  // 监听连接状态变化
  StreamSubscription<BluetoothConnectionState>? _connectionSubscription;

  // 获取已连接设备
  BluetoothDevice? get connectedDevice => _handlerBluetoothDevice.device;

  // 通知监听器
  Stream<List<int>>? get notifyStream => _handlerBluetoothDevice.notifyStream;

  // 创建一个 StreamController，类型为 BluetoothConnectState
  final _connectStateController =
      StreamController<CustomBluetoothConnectState>.broadcast();

  // 处理的蓝牙设备
  HandlerBluetoothDevice _handlerBluetoothDevice = HandlerBluetoothDevice();

  // 扫描订阅
  StreamSubscription<List<ScanResult>>? _scanSubscription;

  // 蓝牙设备列表
  final List<ScanResult> _scanResultList = [];

  // 扫描超时时长
  static const Duration _scanTimeout = Duration(seconds: 15);

  // 连接超时时长
  static const Duration _connectTimeout = Duration(seconds: 10);

  // 数据响应监听已开启
  StreamSubscription<List<int>>? _notifyListen;

  // 初始化
  _initialized() {
    FlutterBluePlus.setOptions(showPowerAlert: false);
    // 蓝牙连接状态
    bluetoothConnectState.listen((event) {
      switch (event) {
        case CustomBluetoothConnectState.connected:
          break;
        default:
          _notifyListen?.cancel();
          _notifyListen = null;
          _handlerBluetoothDevice.device = null;
          break;
      }
    });
  }

  // 开始扫描【目标】蓝牙设备。
  /// [identyId] 目标设备的唯一标识符,可以为remoteId或sn
  Future<bool> search(
    String identyId, {
    VoidCallback? onTimeout,
    Duration? timeout,
    Function(CustomScanResult)? callbackScanResults,
  }) {
    final controller = StreamController<bool>();
    startScan(
      timeout: timeout,
      onTimeout: onTimeout,
      callbackScanResults: (List<CustomScanResult> scanResults) {
        for (var result in scanResults) {
          if (result.device.remoteId.str == identyId ||
              result.sn == identyId ||
              result.device.advName == identyId) {
            // 找到目标设备
            if (callbackScanResults != null) {
              callbackScanResults(result);
            }
            controller.sink.add(true);
          }
        }
      },
    );
    return controller.stream.first;
  }

  /// 开始扫描蓝牙设备。
  ///
  /// [timeout] 指定扫描设备的持续时间。
  /// [callbackScanResults] 是一个回调函数，传递找到的设备列表。
  /// [filterDuplicate] 是否过滤重复蓝牙设备。
  Future<void> startScan({
    Duration? timeout,
    VoidCallback? onTimeout,
    List<Guid>? serviceUuids,
    CallbackScanResults? callbackScanResults,
    bool filterDuplicate = true,
  }) async {
    // 检查设备是否支持蓝牙
    if (!await FlutterBluePlus.isSupported ||
        await FlutterBluePlus.adapterState.first != BluetoothAdapterState.on) {
      _connectStateController.add(CustomBluetoothConnectState.unavailable);
      throw Exception('Bluetooth is not supported or not turned on');
    }
    // 取消之前的扫描订阅
    _cancelScanningSubscription();
    // 清空设备列表
    _scanResultList.clear();

    debugPrint('【$runtimeType】$blue 开始扫描蓝牙设备');
    _connectStateController.add(CustomBluetoothConnectState.isScanning);

    // 监听扫描结果
    _scanSubscription =
        FlutterBluePlus.scanResults.listen((List<ScanResult> results) async {
      for (ScanResult result in results) {
        if (_hasRequiredServices(result, serviceUuids ?? [])) {
          if (filterDuplicate) {
            if (!_scanResultList.contains(result)) {
              _scanResultList.add(result);
            }
          } else {
            _scanResultList.add(result);
          }
        }
      }
      // 回调扫描到的设备
      if (callbackScanResults != null && (!_scanningHasStopped())) {
        callbackScanResults(
          _scanResultList
              .map((result) => CustomScanResult.fromScanResult(result))
              .toList(),
        );
      }
    });

    // 开始扫描
    await FlutterBluePlus.startScan(withServices: serviceUuids ?? []);

    // 设置超时
    Future.delayed(timeout ?? _scanTimeout, () async {
      if (_scanningHasStopped()) return;
      debugPrint('【$runtimeType】$yellow 扫描超时');
      // 超时回调
      if (onTimeout != null) {
        onTimeout();
      }
      // 扫描结束
      await stopScan();
    });
  }

  // 停止扫描，是否跳过idle状态，【当连接指定设备时，可能需要跳过idle状态，保证搜索连接的连续性，不会被idle所打断connecting状态】
  Future<void> stopScan({
    bool isSkipIdleState = false,
  }) async {
    if (_scanningHasStopped()) return;
    _cancelScanningSubscription();
    if (!isSkipIdleState) {
      _connectStateController.add(CustomBluetoothConnectState.idle);
    }
    debugPrint('【$runtimeType】$red 停止扫描');
    return FlutterBluePlus.stopScan();
  }

  // 连接设备
  Future<bool> connectDevice<T extends BluetoothUuidAdapterBase>(
    BluetoothDevice device,
    List<T> bluetoothAdapter, {
    Duration? timeout,
    VoidCallback? onTimeout,
    int maxRetries = 1,
  }) async {
    final completer = Completer<bool>();
    int retries = 0;
    while (true) {
      try {
        // 停止扫描
        await stopScan();
        // 断开连接
        await disconnect();
        debugPrint(
            '【$runtimeType】$blue 连接设备: ${device.advName} (${device.remoteId})${retries > 0 ? " - 重试 #$retries" : ""}');
        // 连接中
        _connectStateController.add(CustomBluetoothConnectState.connecting);
        // 连接设备
        await device.connect().timeout(
          timeout ?? _connectTimeout,
          onTimeout: () {
            if (onTimeout != null) {
              onTimeout();
            }
          },
        );
        // 适配服务和特征
        _handlerBluetoothDevice = await ServiceCharacteristicsAdapter(
          device,
          bluetoothAdapter,
          await device.discoverServices(),
        ).getMatchAdapter();
        // 连接成功
        _connectStateController.add(CustomBluetoothConnectState.connected);
        if (!completer.isCompleted) {
          completer.complete(true);
          debugPrint(
              '【$runtimeType】$blue 连接成功: ${connectedDevice?.advName} (${connectedDevice?.remoteId})');
        }
        // 开始监听断开状态
        _connectionSubscription = device.connectionState.listen((state) {
          if (state == BluetoothConnectionState.disconnected) {
            // 断开连接
            _connectStateController
                .add(CustomBluetoothConnectState.disconnected);
            // 取消连接状态监听
            _connectionSubscription?.cancel();
          }
        });
        break; // Connection successful, exit the loop
      } catch (e) {
        await disconnect();
        retries++;
        if (retries > maxRetries) {
          if (!completer.isCompleted) {
            completer.complete(false);
          }
          debugPrint(
              'Connection failed for device ${device.advName} (${device.remoteId}): ${e.toString()}');
          break; // Exit the loop after max retries
        } else {
          debugPrint('【$runtimeType】$red 连接失败,准备重试 #$retries: ${e.toString()}');
          // Add a small delay before retrying
          await Future.delayed(const Duration(milliseconds: 300));
        }
      }
    }
    return completer.future;
  }

  // 断开连接
  Future<void> disconnect() async {
    if (connectedDevice == null) return;
    debugPrint(
        '【$runtimeType】$red 断开连接： ${connectedDevice?.advName} (${connectedDevice?.remoteId})');
    // 断开连接
    await connectedDevice!.disconnect();
    _handlerBluetoothDevice = HandlerBluetoothDevice();
    _scanResultList.clear();
    _cancelScanningSubscription();
    _connectStateController.add(CustomBluetoothConnectState.disconnected);
  }

  // 【 写 】蓝牙数据
  Future<List<int>>
      write<S extends HandlerSettingsBase, T extends BluetoothInterceptor>(
    S handlerSettings,
    List<int> data, {
    bool withoutResponse = false,
    T? bluetoothInterceptor,
    Duration? timeout,
  }) async {
    if (connectedDevice == null ||
        _handlerBluetoothDevice.bluetoothWriteCharacteristic == null ||
        connectedDevice?.isConnected == false) {
      debugPrint('【$runtimeType】蓝牙设备未连接或写入特征未找到');
      await disconnect();
      throw Exception(
          'Bluetooth device is not connected or write characteristic not found');
    }

    // 添加请求响应通知（只监听一次）
    _setupNotify(handlerSettings, bluetoothInterceptor: bluetoothInterceptor);

    // 拦截请求数据
    final reqData = bluetoothInterceptor?.requestInterception(data) ?? data;

    // 消息id校验
    final msgIds = handlerSettings.getRequestMsgId(reqData);
    if (msgIds.length != 1) {
      throw Exception('仅支持单包发送, 当前消息ID: ${msgIds.join(",")}');
    }
    final msgId = msgIds.first;
    if (handlerSettings.timeoutHelper.responseStreamMap.containsKey(msgId)) {
      debugPrint(
          '❌ ${connectedDevice?.advName} (${connectedDevice?.remoteId}): Request ID $msgId already exists');
      throw Exception('Request ID $msgId already exists');
    }

    // 写入数据
    await _write(handlerSettings, reqData, withoutResponse: withoutResponse);

    // 响应流
    final controller = StreamController<List<int>>();
    handlerSettings.timeoutHelper.responseStreamMap[msgId] =
        WaittingStreamController(
      controller,
      DateTime.now(),
      timeout ?? const Duration(seconds: 5),
    );
    return controller.stream.first;
  }

  // 通知监听，只注册一次
  void _setupNotify<S extends HandlerSettingsBase,
      T extends BluetoothInterceptor>(
    S handlerSettings, {
    T? bluetoothInterceptor,
    bool withoutResponse = false,
  }) {
    if (_notifyListen != null) return;

    _notifyListen = notifyStream?.listen((data) {
      if (data.isEmpty) return;

      // 响应数据拦截，当响应被组包后，rspList长度可能大于1
      final rspList =
          bluetoothInterceptor?.responseInterception(data) ?? [data];
      for (int i = 0; i < rspList.length; i++) {
        // 因为组包在拦截器中处理，所以这里不需要再处理，所以只取第一个msgId
        final msgIds = handlerSettings.getResponseMsgId(rspList[i]);
        final controller = handlerSettings
            .timeoutHelper.responseStreamMap[msgIds.first]?.streamController;
        if (controller != null) {
          controller.add(rspList[i]);
          controller.close();
          handlerSettings.timeoutHelper.responseStreamMap.remove(msgIds.first);
          debugPrint(
              '【$runtimeType】$blue 响应数据: ${Utils.uint8ListToHexString(rspList[i])}');
        }
      }

      // 处理响应数据，当msgIds.length > 1时，表示该响应数据包含多个请求的响应

      // 并发请求处理
      final queue = handlerSettings.timeoutHelper.requestQueue;
      if (queue.isNotEmpty) {
        if (handlerSettings.supportsConcurrentRequests) {
          var nextReqList = <int>[];
          var removedList = <List<int>>[];
          for (var reqItem in queue) {
            if (nextReqList.length + reqItem.length <=
                handlerSettings.concurrentRequestsMaxLength) {
              nextReqList.addAll(reqItem);
              removedList.add(reqItem);
            }
          }
          queue.removeWhere((item) => removedList.contains(item));
          handlerSettings.timeoutHelper.requestQueue
            ..clear()
            ..addAll(queue);
          _write(handlerSettings, nextReqList,
              withoutResponse: withoutResponse, addToQueue: false);
        } else {
          final nextReqList = queue.removeFirst();
          _write(handlerSettings, nextReqList,
              withoutResponse: withoutResponse);
        }
        debugPrint('【$runtimeType】$green 队列请求');
      }
    });
  }

  // 写入数据
  Future<void> _write<S extends HandlerSettingsBase>(
    S handlerSettings,
    List<int> data, {
    bool withoutResponse = false,
    bool addToQueue = true,
  }) async {
    void send() {
      debugPrint(
          '【$runtimeType】$white 写入数据: ${Utils.uint8ListToHexString(data)}');
      handlerSettings.timeoutHelper.startTimeoutCheck();
      _handlerBluetoothDevice.bluetoothWriteCharacteristic!
          .write(data, withoutResponse: withoutResponse);
    }

    if (handlerSettings.supportsConcurrentRequests && addToQueue) {
      if (handlerSettings.timeoutHelper.responseStreamMap.isEmpty) {
        send();
      } else {
        debugPrint(
            '【$runtimeType】$white 写入数据: ${Utils.uint8ListToHexString(data)} 【$purple 加入队列】');
        handlerSettings.timeoutHelper.requestQueue.add(data);
      }
    } else {
      send();
    }
  }

  // 【 读 】蓝牙数据
  Future<List<int>> read(BluetoothCharacteristic characteristic) async {
    throw Exception('Read unsupported');
  }

  // 检查设备是否包含所需的服务
  bool _hasRequiredServices(ScanResult result, List<Guid> serviceUuids) {
    if (result.advertisementData.advName.isEmpty) {
      return false;
    } else {
      if (serviceUuids.isEmpty) {
        return true;
      } else {
        return result.advertisementData.serviceUuids
            .any((uuid) => serviceUuids.contains(uuid));
      }
    }
  }

  // 取消扫描订阅
  void _cancelScanningSubscription() {
    if (_scanningHasStopped()) return;
    _scanSubscription?.cancel();
    _scanSubscription = null;
    debugPrint('【$runtimeType】$red 取消扫描订阅');
  }

  // 扫描已停止
  bool _scanningHasStopped() => _scanSubscription == null;
}
